package cn.superchart.common.base;
import cn.hutool.core.util.StrUtil;
import cn.superchart.common.enums.ExceptionEnum;
import cn.superchart.common.exception.ScException;
import cn.superchart.common.utils.Checker;
import cn.superchart.common.utils.QueryBuilder;
import cn.superchart.common.utils.ScUserContext;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.dozermapper.core.DozerBeanMapper;
import com.google.common.collect.Lists;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

@Slf4j
public class BaseServiceImpl<E extends BaseEntity,M extends BaseMapper<E>> extends ServiceImpl<M, E> implements BaseService {

	@Resource
	private DozerBeanMapper dozerBeanMapper;

	private final Class<E> entityClz;

    protected QueryWrapper<E> queryWrapper(){
        return new QueryWrapper<>();
	}
	protected QueryWrapper<E> queryWrapper(BasePage param){
		QueryWrapper<E> queryWrapper = new QueryWrapper();
		if(Checker.BeNotNull(param)){
			QueryBuilder.buildQueryParam(param,queryWrapper);
		}
		if(Checker.BeNotEmpty(param.getDesc())){
			param.getDesc().forEach(desc->{
				queryWrapper.orderByDesc(StrUtil.toUnderlineCase(desc));
			});
		}if(Checker.BeNotEmpty(param.getAsc())){
			param.getAsc().forEach(asc->{
				queryWrapper.orderByAsc(StrUtil.toUnderlineCase(asc));
			});
		}
		return queryWrapper;
	}


	public <P>Page<P> page(BasePage basePageParam,Class<? extends BaseParam> clz) {
		QueryWrapper<E> queryWrapper =queryWrapper(basePageParam);
		Page<E> page = super.page(basePageParam.defaultPage(),queryWrapper);
		Page<P> pageRes = (Page<P>) copyProperties(page,clz);
		return  pageRes;
	}


	public Page<E> page(BasePage basePageParam) {
		QueryWrapper<E> queryWrapper =queryWrapper(basePageParam);
		Page<E> page = super.page(basePageParam.defaultPage(),queryWrapper);
		return  page;
	}

	protected List listToEmpty(List data){
		return  Checker.BeNotEmpty(data) ? data: Lists.newArrayList();
	}


	protected E pToE(BaseParam p){
		if(Checker.BeNotNull(p)){
			return dozerBeanMapper.map(p, entityClz);
		}
		return null;
	}

	protected <P extends BaseParam> P eToP(E e, Class<P> pClass){
		if(Checker.BeNotNull(e)){
			return dozerBeanMapper.map(e, pClass);
		}
		return null;
	}

	protected void copyProperties(Object source,Object target){
		if(Checker.BeNotNull(source) && Checker.BeNotNull(target)){
			dozerBeanMapper.map(source,target);
		}
	}


	protected  <T>Page<T> copyProperties(Page<E> pageE,Class<T> pClass){
		Page<T> page = new Page<>();
		if(Checker.BeNotNull(pageE) && Checker.BeNotEmpty(pageE.getRecords())){
			page.setTotal(pageE.getTotal());
			page.setPages(pageE.getPages());
			page.setCurrent(pageE.getCurrent());
			page.setSize(pageE.getSize());
			List<T> rows = new ArrayList<>();
			if(Checker.BeNotEmpty(pageE.getRecords())){
				for(E e:pageE.getRecords()){
					T data = dozerBeanMapper.map(e,pClass);
					rows.add(data);
				}
				page.setRecords(rows);
			}
		}
		return page;
	}


	protected <T> T copyProperties(Object source,Class<T> target){
		if(Checker.BeNotNull(source) && Checker.BeNotNull(target)){
			return dozerBeanMapper.map(source,target);
		}
		return null;
	}


	protected String getUserId(){
		return ScUserContext.getUserId();
	}

	protected String getUserId(boolean force){
		return ScUserContext.getUserId(force);
	}

	protected String getAccount(){
		return ScUserContext.getAccount();
	}


	public BaseServiceImpl(){
		Type genType = getClass().getGenericSuperclass();
		Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
		entityClz = (Class<E>) params[0];
	}

	public <P extends BaseParam> String saveData(P param){
		if(Checker.BeNotNull(param)){
			E e =dozerBeanMapper.map(param,entityClz);
			super.save(e);
			return e.primaryKey();
		}
		return null;
	}

	@Override
	public <P extends BaseParam> void saveData(List<P> params) {
		if(Checker.BeNotEmpty(params)){
			List<E> entityes = new ArrayList<>();
			for(P param:params){
				E e =dozerBeanMapper.map(param,entityClz);
				entityes.add(e);
			}
			super.saveBatch(entityes);
		}
	}

	@Override
	public  <P extends BaseParam> boolean updateData(P param) {
		if(Checker.BeNotNull(param)){
			String primaryKey =param.primaryKey();
			if(Checker.BeBlank(primaryKey)){
				throw new ScException(ExceptionEnum.PK_CAN_NOT_BLANK);
			}
			E e =queryEntity(primaryKey);
			if(Checker.BeNotNull(e)){
				dozerBeanMapper.map(param,e);
				return super.updateById(e);
			}
		}
		return false;
	}

	@Override
	public <P> P queryData(Serializable pk, Class clz) {
		E e =queryEntity(pk);
		if(Checker.BeNotNull(e)){
			return (P) dozerBeanMapper.map(e,clz);
		}
		return null;
	}

	@Override
	public  Long count(QueryWrapper<BaseEntity> queryWrapper) {
		return super.count((Wrapper<E>) queryWrapper);
	}

	@Override
	public boolean delete(Serializable pk) {
		return baseMapper.deleteById(pk) >0;
	}

	@Override
	public List<E> listData() {
		QueryWrapper<E> queryWrapper = new QueryWrapper<>();
		queryWrapper.last("LIMIT 5000");
		return super.list(queryWrapper);
	}


	@Override
	public E queryEntity(Serializable pk) {
		if(Checker.BeNotNull(pk)){
			return super.getById(pk);
		}
		return null;
	}

}
